package com.atguigu.item.service.impl;

import com.atguigu.item.service.LockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LockServiceImpl  implements LockService {
    @Autowired
    private StringRedisTemplate  redisTemplate;

    /**
     * 阻塞式加锁  如果获取锁失败就一直等待获取锁 直到成功
     * @return
     * @throws InterruptedException
     */
    @Override
    public String lock() throws InterruptedException {
        //加锁失败不能跳出方法 继续while循环
        String uuid = UUID.randomUUID().toString();
        while(!redisTemplate.opsForValue().setIfAbsent("lock",uuid,30, TimeUnit.SECONDS)){
            //加锁成功以后。
            TimeUnit.MILLISECONDS.sleep(10);
        }
        //加锁成功
        return uuid;
    }

    /**
     * 释放锁
     * @param uuid
     */
    @Override
    public void unlock(String uuid) {
     //得到的锁值可能与我们加锁的值不一样（锁过期 redis直接删除锁 导致我们用的是别人的锁）
        // TODO 删锁+获取值 是同时操作 具有原子性
        //TODO 脚本无论多长 都是原子操作
        String script = "if redis.call(\"get\",KEYS[1]) == ARGV[1]\n" +
                "then\n" +
                "    return redis.call(\"del\",KEYS[1])\n" +
                "else\n" +
                "    return 0\n" +
                "end";
        //删锁成功
         //TODO 返回0 删锁失败 有可能是别人的锁  返回值 1 删锁成功
        Long lock = redisTemplate.execute(
                new DefaultRedisScript<>(script, Long.class),
                Arrays.asList("lock"),
                uuid
        );
        System.out.println("删除结果"+lock);


    }
}
